#include "stdafx.h"
#include "common/merger.h"
#include "resource.h"
#include "PdfTools2.h"
#include <fstream>

class ATL_NO_VTABLE CPdfMerger :
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CPdfMerger, &CLSID_PdfMerger>,
	public ISupportErrorInfo,
	public IDispatchImpl<IPdfMerger, &IID_IPdfMerger, &LIBID_PdfTools, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
	CPdfMerger();

	DECLARE_REGISTRY_RESOURCEID(IDR_PDFMERGER)
	DECLARE_NOT_AGGREGATABLE(CPdfMerger)
	DECLARE_PROTECT_FINAL_CONSTRUCT()

private:
	BEGIN_COM_MAP(CPdfMerger)
		COM_INTERFACE_ENTRY(IPdfMerger)
		COM_INTERFACE_ENTRY(IDispatch)
		COM_INTERFACE_ENTRY(ISupportErrorInfo)
	END_COM_MAP()

	HRESULT FinalConstruct();
	void	FinalRelease();

	// ISupportsErrorInfo
	STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);

	// IPdfMerger
	STDMETHOD(Open)(BSTR path, BSTR password);
	STDMETHOD(Append)(BSTR path, BSTR password);
	STDMETHOD(Close)(void);

	CAutoPtr<Pdf::Merger>	merger;
	CAutoPtr<std::ofstream> output;
};

// =====================================================================

inline CPdfMerger::CPdfMerger()
{	}

inline HRESULT CPdfMerger::FinalConstruct()
{	return S_OK;	}

inline void CPdfMerger::FinalRelease()
{	Close();	}

STDMETHODIMP CPdfMerger::InterfaceSupportsErrorInfo(REFIID riid)
{
	static const IID* arr[] = { &IID_IPdfMerger };

	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i)
		if (InlineIsEqualGUID(*arr[i],riid))
			return S_OK;

	return S_FALSE;
}

STDMETHODIMP CPdfMerger::Open(BSTR path, BSTR password)
{	
	try
	{
		CAutoPtr<std::ofstream> newOutput( new std::ofstream( CStringA(path), std::ios::binary ) );

		if ( !*newOutput )
		{
			Error( ::AtlGetErrorDescription(ERROR_PATH_BUSY), IID_IPdfMerger, ERROR_PATH_BUSY );
			return ERROR_PATH_BUSY;
		}

		CAutoPtr<Pdf::Merger> newMerger( new Pdf::Merger(*newOutput) );

		output = newOutput;
		merger = newMerger;

		return S_OK;
	}
	catch (std::exception &e)
	{
		Error( CComBSTR( e.what() ), IID_IPdfMerger, E_FAIL );
		return E_FAIL;
	}
	catch (...)
	{
		Error( ::AtlGetErrorDescription(E_FAIL), IID_IPdfMerger, E_FAIL );
		return E_FAIL;
	}
}

STDMETHODIMP CPdfMerger::Append(BSTR path, BSTR password)
{	
	try
	{
		if ( merger == 0)
		{
			Error( ::AtlGetErrorDescription(ERROR_NOT_READY), IID_IPdfMerger, ERROR_NOT_READY );
			return ERROR_NOT_READY;
		}

		std::ifstream input( CStringA(path), std::ios::binary );

		if ( !input )
		{
			Error( ::AtlGetErrorDescription(ERROR_FILE_NOT_FOUND), IID_IPdfMerger, ERROR_FILE_NOT_FOUND );
			return ERROR_FILE_NOT_FOUND;
		}

		merger->append( input, static_cast<PCSTR>( CStringA(password) ) );
		return S_OK;
	}
	catch (std::exception &e)
	{
		Error( CComBSTR( e.what() ), IID_IPdfMerger, E_FAIL );
		return E_FAIL;
	}
	catch (...)
	{
		Error( ::AtlGetErrorDescription(E_FAIL), IID_IPdfMerger, E_FAIL );
		return E_FAIL;
	}
}

STDMETHODIMP CPdfMerger::Close()
{
	merger.Free();
	output.Free();
	return S_OK;	
}

// =====================================================================

OBJECT_ENTRY_AUTO(__uuidof(PdfMerger), CPdfMerger)